<?xml version="1.0" encoding="UTF-8"?>
<!--

       Copyright 2006-2021 the original author or authors.

       Licensed under the Apache License, Version 2.0 (the "License");
       you may not use this file except in compliance with the License.
       You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

       Unless required by applicable law or agreed to in writing, software
       distributed under the License is distributed on an "AS IS" BASIS,
       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       See the License for the specific language governing permissions and
       limitations under the License.

-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>MyBatis Dynamic SQL with Kotlin Usage Notes</title>
  <link rel="stylesheet" type="text/css" href="../mbgstyle.css" />
</head>
<body>
<h1>MyBatis Dynamic SQL with Kotlin Usage Notes</h1>
<p>This page is a short introduction to using the classes generated for the MyBatis3Kotlin runtime
These classes
are dependent on the <a href="http://www.mybatis.org/mybatis-dynamic-sql/docs/introduction.html">MyBatis Dynamic SQL</a>
library version 1.1.4 or higher. Please refer to that site for full information
about how the library works. In particular, see the 
<a href="https://mybatis.org/mybatis-dynamic-sql/docs/kotlinMyBatis3.html">Kotlin Usage Page</a> for full details.</p>

<h2>Generated Files</h2>
<p>For each introspected table, the generator will generate four Kotlin files:</p>
<ol>
  <li>A Kotlin data class that represents a row in the table. By default the class will be named based
    on the table name</li>
  <li>A "support" class that includes a table definition and column definitions for the database table</li>
  <li>A mapper interface with the basic MyBatis mapper methods</li>
  <li>A mapper extensions file with extension methods that simplify and reuse the methods in the basic interface.
  This is similar to the default interface methods generated in the other runtimes, but it is accomplished
  with extension methods in Kotlin. </li>
</ol>

<p>Important notes about the generated objects:</p>
<ul>
  <li>No XML is generated</li>
  <li>No separate "Example" class is generated</li>
  <li>There are no separate "with BLOBs" and "without BLOBs" methods.  If your table includes BLOB fields, then
      they are included in all operations.</li>
  <li>Model classes are always generated in the "flat" model meaning there is no separate primary key class or BLOBs class</li>
  <li>Java 8 or higher is required</li>
  <li>Any recent version of Kotlin should work</li>
  <li>MyBatis 3.4.2 or higher is required</li>
  <li>MyBatis Dynamic SQL 1.1.4 or higher is required</li>
</ul>

<h2>Format of the "Support" classes</h2>
<p>A "support" class is created for each table.  The support class includes a definition of the table and all the columns
in the table.  These items are used as input to the code generated in the mappers - most often for the where clauses you
will write.</p>

<p>For example, suppose there is a table "TABLE_CODE" in schema "MYSCHEMA".  Further suppose that table has "ID" and
"DESCRIPTION" columns.  The generated support class will look like this: </p>

<pre>
package example

import java.sql.JDBCType
import org.mybatis.dynamic.sql.SqlTable
import org.mybatis.dynamic.sql.util.kotlin.elements.column

object TableCodeDynamicSqlSupport {
    val tableCode = TableCode()
    val id = tableCode.id
    val description = tableCode.description

    class TableCode : SqlTable("MYSCHEMA.TABLE_CODE") {
        val id = column&lt;Int&gt;(name = "ID", jdbcType = JDBCType.INTEGER)
        val description = column&lt;String&gt;(name = "DESCRIPTION", jdbcType = JDBCType.VARCHAR)
    }
}
</pre>

<p>In your code you can import that table object and/or each generated column (Kotlin does not support a star "*" import in this case).
With these imports you can refer to the fields
in either a direct or qualified manner - "id" or "TableCode.id".</p>

<h2>Usage of the Mapper Classes</h2>
<p>The following methods work the same as the other runtimes and we won't cover them here:</p>
<ul>
  <li>Delete by Primary Key</li>
  <li>Insert - will insert nulls</li>
  <li>insert selective - ignores null properties</li>
  <li>Select by Primary Key</li>
  <li>Update by Primary Key - will set null values</li>
  <li>Update by Primary Key Selective - ignores null values</li>
</ul>

<p>There are no "by example" methods. Instead, there are general purpose methods that allow you to specify a
where clause with a lambda.  The generator will create the following general:</p>
<ul>
  <li>count</li>
  <li>delete</li>
  <li>select</li>
  <li>selectDistinct</li>
  <li>selectOne</li>
  <li>update</li>
</ul>

<p>Each of these methods includes support for a very flexible WHERE clause that can be specified with a lambda. If you
don't need a where clauses, there are utility functions that mean "all rows".</p>

<p>For example, you can retrieve the total number of rows in a table by calling the count method without a WHERE clause.
That code looks like this:</p>

<pre>
  val totalRows = mapper.count { allRows() }
</pre>


<p>You can retrieve all rows in a table by calling select without a WHERE clause like this:</p>

<pre>
  val allRecords = mapper.select { allRows() }
</pre>

<p>It is far more interesting to add WHERE clauses to these methods.  To add support for WHERE clauses, you should import the 
elements from the support class as shown above, and you should also import the SqlBuilder support.  Then you can code arbitrarily
complex where clauses, and "ORDER BY" phrases as shown below:</p>

<pre>
// import the generated "support" items...
import example.TableCodeDynamicSqlSupport.tableCode
import example.TableCodeDynamicSqlSupport.description
import example.TableCodeDynamicSqlSupport.id

// import MyBatis Dynamic SQL where support
import org.mybatis.dynamic.sql.SqlBuilder.*

class SomeService {

    fun simpleWhere() {
        ...
        // Simple WHERE clause
        val records = mapper.select {
            where(id, isEqualTo(3))
        }
        ...
    }

    fun complexWhere1() {
        ...
        // Simple WHERE clause with OR
        val records = mapper.select {
            where(id, isEqualTo(3))
            or(description, isLike("f%"))
        }
        ...
    }

    fun complexWhere2() {
        ...
        // complex WHERE and ORDER BY
        val records = mapper.select {
            where(id, isLessThan(10)) {
                and(description, isEqualTo("foo"))
            }
            or(description, isLike("b%"))
            orderBy(id.descending())
        }        
        ...
    }
}
</pre>

<h2>Update Method Usage</h2>
<p>The generated update statement is very flexible. You can now create any arbitrary update,
as well as updates that mimic the old updateByExample and updateByExampleSelective methods.</p>

<pre>
// import the generated "support" items...
import example.TableCodeDynamicSqlSupport.tableCode
import example.TableCodeDynamicSqlSupport.description
import example.TableCodeDynamicSqlSupport.id

// import MyBatis Dynamic SQL where support
import org.mybatis.dynamic.sql.SqlBuilder.*

class SomeService {

    fun simpleUpdate() {
        ...
        // Flexible update - no backing record needed
        val rows = mapper.update {
            set(id).equalTo(1)
            set(description).equalToNull()
            where(id, isEqualTo(3))
        }
        ...
    }

    fun updateByExample(row: TableCode) {
        ...
        // Update like the old updateByExample method
        val rows =  mapper.update {
            updateAllColumns(row)
            where(id, isEqualTo(3))
            or(description, isLike("f%"))
        }
        ...
    }

    fun updateByExampleSelective(row: TableCode) {
        ...
        // Update like the old updateByExampleSelective method
        val rows =  mapper.update {
            updateSelectiveColumns(row)
            where(id, isEqualTo(3))
            or(description, isLike("f%"))
        }
        ...
    }
}
</pre>

<h2>New Plugins</h2>
<p>Because the *ByExample methods are not generated, it no longer makes sense to control method generation via the properties
on an XML <code>&lt;table&gt;</code> configuration like <code>enableInsert</code>,
<code>enableSelectByExample</code>, etc. So this new runtime will ignore any of those properties. If you wish
to have this level of control over what is generated, you can accomplish that with a plugin. We have also included
the following plugins for general use with this runtime:</p>
<ul>
  <li><code>org.mybatis.generator.plugins.dsql.DisableDeletePlugin</code> - disables all generated delete methods</li>
  <li><code>org.mybatis.generator.plugins.dsql.DisableInsertPlugin</code> - disables all generated insert methods</li>
  <li><code>org.mybatis.generator.plugins.dsql.DisableUpdatePlugin</code> - disables all generated update methods</li>
  <li><code>org.mybatis.generator.plugins.dsql.ReadOnlyPlugin</code> - disables all generated delete, insert,
  and update methods</li>
</ul>

</body>
</html>
